﻿namespace MicroCloud.Entity
{
    /// <summary>
    /// 实体框架核心模块(EntityFrameworkCore)基类
    /// </summary>
    [Description("实体框架核心模块(EFCore)")]
    [DependsOnPacks(typeof(EventBusPack))]
    public abstract class EntityFrameworkCorePackBase : PackBase
    {
        //字段
        private static bool _optionsValidated;

        #region "属性"
        #region "获取 模块级别，级别越小越先启动"
        /// <summary>
        /// 获取 模块级别，级别越小越先启动
        /// </summary>
        public override PackLevel Level => PackLevel.Framework;
        #endregion
        #region "获取 模块启动顺序编号"
        /// <summary>
        /// 获取 模块启动顺序编号
        /// <para>模块启动的顺序先按级别启动，级别内部再按此顺序启动，级别默认为0，表示无依赖，需要在同级别有依赖顺序的时候，再重写为 >0 的顺序值。</para>
        /// </summary>
        public override int OrderNo => 0;
        #endregion

        #region "获取 数据库类型"
        /// <summary>
        /// 获取 数据库类型
        /// </summary>
        protected abstract DatabaseType DatabaseType { get; }
        #endregion

        #endregion

        #region "方法"
        #region "将模块服务添加到依赖注入服务容器中"
        /// <summary>
        /// 将模块服务添加到依赖注入服务容器中
        /// </summary>
        /// <param name="services">依赖注入服务容器</param>
        /// <returns></returns>
        public override IServiceCollection AddServices(IServiceCollection services)
        {
            services.TryAddScoped<IAuditEntityProvider, AuditEntityProvider>();
            services.TryAddScoped<IEntityEntryProvider, EntityEntryProvider>();
            services.TryAddScoped(typeof(IRepository<,>), typeof(Repository<,>));
            services.AddScoped<IUnitOfWork, UnitOfWork>();
            services.AddScoped<IConnectionStringProvider, ConnectionStringProvider>();
            services.AddScoped<IMasterSlaveSplitPolicy, MasterSlaveSplitPolicy>();

            //键值生成器服务
            services.AddSingleton<IAutoIncreaseKeyGenerator<int>, AutoIncreaseInt32KeyGenerator>();
            services.AddSingleton<IAutoIncreaseKeyGenerator<long>, AutoIncreaseInt64KeyGenerator>();
            services.AddSingleton<ISnowflakeKeyGenerator<int>, Snowflake32KeyGenerator>();
            services.AddSingleton<ISnowflakeKeyGenerator<long>, Snowflake64KeyGenerator>();

            services.AddSingleton<IEntityManager, EntityManager>();
            services.AddSingleton<DbContextModelCache>();

            services.AddScoped<IEntityQuerier, EntityQuerier>();

            services.AddSingleton<ISlaveDatabaseSelector, RandomSlaveDatabaseSelector>();
            services.AddSingleton<ISlaveDatabaseSelector, SequenceSlaveDatabaseSelector>();
            services.AddSingleton<ISlaveDatabaseSelector, WeightSlaveDatabaseSelector>();

            //设置-->事务通知存储过程
            services.AddSingleton<IProcedureHandler, SP_TransactionNotification>();

            //注册事件委托
            services.AddEventHandler<EntityEntryEventHandler>();

            return services;
        }
        #endregion
        #region "应用模块服务"
        /// <summary>
        /// 应用模块服务
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public override void UsePack(IServiceProvider provider)
        {
            var dbContextOptions = provider?.GetMicroCloudOptions()?.DbContexts;
            if (!_optionsValidated)
            {
                if (dbContextOptions.IsNullOrEmpty())
                {
                    throw new Exception(I18N.T("配置文件中找不到数据上下文的配置，请配置 MicroCloud:DbContexts 节点"));
                }

                foreach (var options in dbContextOptions)
                {
                    string msg = options.Value.Error;
                    if (!msg.IsMissing())
                    {
                        throw new Exception(I18N.T("数据库 {0} 配置错误：{1}。", options.Key, msg));
                    }
                }

                _optionsValidated = true;
            }

            if (dbContextOptions.Values.All(m => m.DatabaseType != DatabaseType))
            {
                return;
            }

            IEntityManager manager = provider.GetRequiredService<IEntityManager>();
            manager.Initialize();

            IsEnabled = true;
        }
        #endregion

        #endregion

    }

}
